<?php
/**
 * ws.php
 *
 * @copyright   2023 jsjsem.cn - All Rights Reserved
 * @link        http://thingsworld.com.cn/
 * @author      stiffer.chen <chenl@thingsworld.com.cn>
 * @created     2023-02-24 14:10:51
 * @modified    2023-02-24 14:10:51
 *
 */

const SOCKET_URL = '0.0.0.0';
const SOCKET_PORT = 9502;

class ws
{
    private $url;
    private $port;
    private $server;
    private $clientIds;

    private $redisClient;

    private static $instance;

    public function __construct()
    {
        $this->url = SOCKET_URL;
        $this->port = SOCKET_PORT;
        $this->initServer();

        $this->redisClient = new Redis();
        $this->redisClient->connect('127.0.0.1');
    }

    /**
     * @return mixed
     */
    public static function getInstance()
    {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function initServer()
    {
        $that = $this;
        $server = new \Swoole\WebSocket\Server($this->url, $this->port);
        $server->on('start', function ($server) use ($that) {
            $that->onStart($server);
        });
        $server->on('open', function ($server, $req) use ($that) {
            $that->onOpen($server, $req);
        });
        $server->on('message', function ($server, $frame) use ($that) {
            $that->onMessage($server, $frame);
        });
        $server->on('close', function ($server, $fd) use ($that) {
            $that->onClose($server, $fd);
        });
        $this->server = $server;
    }

    public function onStart($server)
    {
        echo "start...\n";
    }

    public function onOpen($server, $req)
    {
        $serverData = $req->server;
        $queryString = $serverData['query_string'] ?? '';
        if (strrpos($queryString, 'type=pusher') === false) {
            $this->redisClient->sAdd('ws_client_ids', strval($req->fd));
        }
        echo "open...\n";
    }

    public function onMessage($server, $frame)
    {
        $message = $frame->data;
        $fds = $this->redisClient->sMembers('ws_client_ids');
        foreach ($fds as $index => $fd) {
            try {
                $this->server->push($fd, $message);
                var_dump('success');
            } catch (Exception $e) {
                $this->redisClient->sRem($fd);
            }
        }
        echo "message...\n";
    }

    public function onClose($server, $fd)
    {
        $this->redisClient->del('ws_client_ids');
        echo "close...\n";
    }

    public function start()
    {
        $this->server->start();
    }
}

ws::getInstance()->start();